import time


def HMSToSeconds(hms):
    seconds = 0
    for s in hms.split(":"):
        seconds = 60 * seconds + float(s)
    return seconds


def SecondsToHMS(seconds):
    tm = time.localtime(seconds)
    return "%.2d:%.2d:%.2d" % (tm.tm_hour, tm.tm_min, tm.tm_sec)


class Timestamp(object):
    def __init__(self, stamp, event=None):  # time can be relative to events, need a current one
        self.stamp = stamp
        self.event = event
        self.absolute = None
        self.periodRelative = None
        self.jamRelative = None

    def Date(self):
        # todo: find the bout date
        return time.time()

    def RelativePeriod(self, value):
        """ Convert a time that is relative to the start of the jam to the actual
        absolute time by adding all the timeouts
        
        """
        # iterate through the current period and add in timeouts
        period = self.event.EnclosingPeriod()
        jam = self.event.EnclosingJam()
        atime = period.timestamp.Absolute() + value
        # go through timeouts, and then subtract the time between the timeout
        # and the start of the next jam (since the timeout duration doesn't include the
        # "up to 30 seconds" of lineup time afterwards)
        stop = None
        duration = None
        for child in period.children:
            if child == self.event:
                break  # we've reached ourselves (don't recurse)
            if child.elementName == "time-out":
                stop = child.timestamp.Absolute()
                duration = 0
                if child['duration']:
                    duration = float(child['duration'])
                    atime += duration
                    #print "Stopping clock at", child.timestamp.TimeStr(), duration
            elif child.elementName == "jam":
                if stop is not None:  # we were in a time out
                    #print "Starting period clock at", child.timestamp.TimeStr()
                    start = child.timestamp.Absolute()
                    if start == stop:  # period based probably
                        pass
                    else:
                        atime = atime + (start - stop) - duration  # ignore previous duration
                    stop = None
            if child == jam:
                break  # we've gone as far as the jam we are in
        return atime

    def HHMMSSStr(self):
        tm = time.localtime(self.Absolute())
        return "%.2d:%.2d:%.2d" % (tm.tm_hour, tm.tm_min, tm.tm_sec)

    def PMMSSStr(self):
        tm = time.localtime(self.Period())
        return "%.2d:%.2d" % (tm.tm_min, tm.tm_sec)

    def TimeStr(self):
        return time.ctime(self.Absolute())

    def Absolute(self):
        if self.absolute is not None:
            return self.absolute
        colonSplit = self.stamp.split(":")
        if len(colonSplit) == 3:  # hh:mm:ss - Absolute
            ts = list(time.localtime(self.Date()))
            ts[3] = int(colonSplit[0])
            ts[4] = int(colonSplit[1])
            ts[5] = int(colonSplit[2])
            self.absolute = time.mktime(ts)
        elif len(colonSplit) == 2:  # mm:ss - period time
            self.absolute = self.RelativePeriod(HMSToSeconds(self.stamp))
        elif len(colonSplit) == 1:
            if self.stamp[:1] == "+":  # relative to start of jam
                jam = self.event.EnclosingJam()
                start = jam.timestamp.Absolute()
                self.absolute = start + float(self.stamp)
            elif self.stamp[:1] == "-":  # relative to end of jam
                jam = self.event.EnclosingJam()
                start = jam.timestamp.Absolute()
                if jam["duration"] is not None:
                    duration = float(jam["duration"])
                else:
                    duration = 120
                self.absolute = start + duration + float(self.stamp)
            else:  # either epoch or period relative
                if self.event.elementName == "period":  # epoch relative
                    self.absolute = float(self.stamp)
                else:  # period relative
                    self.absolute = self.RelativePeriod(float(self.stamp))
        return self.absolute

    def Period(self):
        colonSplit = self.stamp.split(":")
        if len(colonSplit) == 3:  # hh:mm:ss - Absolute
            absolute = self.Absolute()  # convert to absolute first
            # now take the absolute of the period, and subtract time out durations
            period = self.event.EnclosingPeriod()
            atime = absolute - period.timestamp.Absolute()
            stop = None
            duration = None
            for child in period.children:
                if child == self.event:
                    break  # we've reached ourselves (don't recurse)
                if child.elementName == "time-out":
                    stop = child.timestamp.Absolute()
                    duration = 0
                    if child['duration']:
                        duration = float(child['duration'])
                        atime -= duration
                        #print "Stopping clock at", child.timestamp.TimeStr(), duration
                elif child.elementName == "jam":
                    if stop is not None:  # we were in a time out
                        #print "Starting period clock at", child.timestamp.TimeStr()
                        start = child.timestamp.Absolute()
                        if start == stop:  # period based probably
                            pass
                        else:
                            atime -= (start - stop) - duration  # ingore previous duration
                        stop = None
                if child == jam:
                    break  # we've gone as far as the jam we are in
            return atime
        elif len(colonSplit) == 2:  # mm:ss - period time
            return HMSToSeconds(self.stamp)  # good
        elif len(colonSplit) == 1:
            if self.stamp[:1] == "+":  # relative to start of jam
                jam = self.event.EnclosingJam()
                start = jam.timestamp.Period()
                return start + float(self.stamp)
            elif self.stamp[:1] == "-":  # relative to end of jam
                jam = self.event.EnclosingJam()
                start = jam.timestamp.Period()
                if jam["duration"] is not None:
                    duration = float(jam["duration"])
                else:
                    duration = 120
                return start + duration + float(self.stamp)
            else:  # either epoch or period relative
                if self.event.elementName == "period":  # epoch relative
                    return 0  # we are relative to the period, which is epoch relative
                else:  # period relative, which is good
                    return float(self.stamp)


if __name__ == "__main__":
    import DerbyXML

    ts = Timestamp("16:36:00", None)
    print ts.Absolute(), ts.TimeStr()
    bout = DerbyXML.Bout.fromString("""<bout>
    <period timestamp="14:00:00">
        <jam timestamp="14:00:00" duration="63">
        </jam>
        <time-out timestamp="1:20" duration="95" />
        <jam timestamp="1:20" duration="30">
        </jam>
        <jam timestamp="2:20">
            <lead timestamp="+12"/>
        </jam>
    </period>
    </bout>""")
    bout.dumpTimes()

